﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyUtils.CacheService
{

    public interface ICache<TKey,TValue>
    {
        /// <summary>
        /// 获取某个键对应的缓存信息
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns>是否获取成功</returns>
        bool Get(TKey key, out TValue value);

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expiration">过期时间</param>
        void Set(TKey key, TValue value,TimeSpan expiration);

        /// <summary>
        /// 删除某个键对应的缓存
        /// </summary>
        /// <param name="key"></param>
        /// <returns>是否删除成功</returns>
        bool Remove(TKey key);
    }

    /// <summary>
    /// 内存池中的value
    /// </summary>
    /// <typeparam name="T"></typeparam>
    internal class CacheItme<T> : IDisposable
    {
        public T Value { get; }
        public bool NeverExpires { get; }
        public DateTimeOffset Expiration { get; }

        public CacheItme(T value)
        {
            Value = value;
            NeverExpires = true;
        }

        public CacheItme(T value,DateTimeOffset expiration)
        {
            Value = value;
            Expiration = expiration;
            NeverExpires = false;
        }

        /// <summary>
        /// 是否过期
        /// </summary>
        public bool IsExpiration => NeverExpires == false ? DateTimeOffset.UtcNow > Expiration : false;

        public void Dispose()
        {
            //GC.Collect();
            GC.SuppressFinalize(this);
        }
    }

    /// <summary>
    /// 简易缓存
    /// </summary>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TValue"></typeparam>
    public class MemoryCache<TKey, TValue> : ICache<TKey, TValue>
    {
        /// <summary>
        /// 数据存储器
        /// </summary>
        private readonly ConcurrentDictionary<TKey, CacheItme<TValue>> _cache;

        public MemoryCache()
        {
            _cache = new();
        }


        public bool Remove(TKey key)
        {
            if (_cache.TryRemove(key, out var item))
            {
                item.Dispose();
                item = null;
                return true; 
            }
            return false;
        }

        public void Set(TKey key, TValue value, TimeSpan expiration)
        {
            _cache[key] = expiration == TimeSpan.Zero ? new CacheItme<TValue>(value) : new CacheItme<TValue>(value,DateTime.UtcNow.Add(expiration));
        }

        public bool Get(TKey key, out TValue value)
        {
            if (_cache.TryGetValue(key,out var cacheItme)) 
            {
                if (cacheItme.IsExpiration == false) // 未过期
                {
                    value = cacheItme.Value;
                    return true;
                }
                else
                {
                    cacheItme.Dispose();
                    cacheItme = null;
                }
            }
            value = default;
            return false;
        }
    }


    
}
